//  Inside Microsoft Exchange 2007 Web Services 
//  Chapter 11
//
//  Copyright (c) 2007 David Sterling, Ben Spain, Mark Taylor, Huw Upshall, Michael Mainer.  
//  All rights reserved.
//

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using ProxyHelpers.EWS;

namespace CreateOverdueTaskAndComplete
{
    class Program
    {
        static void Main(string[] args)
        {
            ExchangeServiceBinding binding = new ExchangeServiceBinding();
            binding.Url = @"https://yourServer/ews/Exchange.asmx";
            binding.Credentials = new NetworkCredential("username", "password", "domain");
            
            TestOverdueTaskCompletion(binding);
        }

        /// <summary>
        /// Test our CreateOverdueTaskAndComplete method (Listing 11-16)
        /// </summary>
        /// <param name="binding">Binding to use for our call</param>
        /// 
        public static void TestOverdueTaskCompletion(ExchangeServiceBinding binding)
        {
            Console.WriteLine("Daily Recurrence");
            Console.WriteLine("===========================");
            DailyRecurrencePatternType dailyRecurrence = new DailyRecurrencePatternType();
            dailyRecurrence.Interval = 1;
            string subject = "Clean your room " + Environment.TickCount.ToString();

            CreateOverdueTaskAndComplete(binding, dailyRecurrence, subject);
            Console.WriteLine("\r\n\r\n");

            Console.WriteLine("Daily Regenerating");
            Console.WriteLine("===========================");
            DailyRegeneratingPatternType dailyRegenerating =
                                    new DailyRegeneratingPatternType();
            dailyRegenerating.Interval = 1; // 1 day
            subject = "Clean your room " + Environment.TickCount.ToString();
            CreateOverdueTaskAndComplete(binding, dailyRegenerating, subject);
        }


        /// <summary>
        /// Creates an overdue task and marks instances as complete until we are no longer overdue (Listing 11-15)
        /// </summary>
        /// <param name="binding">Binding to use</param>
        /// <param name="recurrencePattern">Recurrence pattern</param>
        /// <param name="subject">Subject</param>
        /// 
        public static void CreateOverdueTaskAndComplete(
                                ExchangeServiceBinding binding, 
                                RecurrencePatternBaseType recurrencePattern, 
                                string subject)
        {
            // First create our recurring task
            //
            ItemIdType id = CreateRecurringTask(binding, subject, recurrencePattern);

            ItemResponseShapeType getItemResponseShape =
                                            new ItemResponseShapeType(
                                    DefaultShapeNamesType.IdOnly,
                                    new PathToUnindexedFieldType(UnindexedFieldURIType.taskDueDate));

            // Grab the recurring task just to get the original due date
            //
            TaskType recurringTask = (TaskType)EWSHelpers.SimpleGetItem(
                                        binding,
                                        id,
                                        getItemResponseShape);
            Console.WriteLine("Original Due Date: " + recurringTask.DueDate.ToString());

            while (true)
            {
                // On each iteration, mark the recurring task as complete
                //
                ItemIdType oneOffId = MarkTaskAsComplete(binding, id);

                // Grab the updated Id and the next due date
                //
                recurringTask = (TaskType)EWSHelpers.SimpleGetItem(
                                            binding,
                                            id,
                                            getItemResponseShape);

                // Grab our updated id with change key.  Remember this is the id of the recurring task, 
                // NOT the one off.
                //
                id = recurringTask.ItemId;

                DateTime newTaskDueDate = recurringTask.DueDate;
                Console.WriteLine("\tNext Due Date: " + newTaskDueDate.ToString());
                if (newTaskDueDate.DayOfYear > DateTime.Now.DayOfYear)
                {
                    Console.WriteLine("We are now up to date!");
                    break;
                }
            }
        }

        /// <summary>
        /// Creates a recurring task given the recurrence pattern
        /// </summary>
        /// <param name="binding">Binding to use</param>
        /// <param name="subject">Subject for task</param>
        /// <param name="recurrencePattern">Recurrence pattern</param>
        /// <returns>Id of newly created task</returns>
        /// 
        public static ItemIdType CreateRecurringTask(
                                        ExchangeServiceBinding binding,
                                        string subject,
                                        RecurrencePatternBaseType recurrencePattern)
        {
            CreateItemType request = new CreateItemType();
            TaskType task = new TaskType();
            TaskRecurrenceType taskRecurrence = new TaskRecurrenceType();
            taskRecurrence.Item = recurrencePattern;

            ExtendedPropertyType taskStamp = new ExtendedPropertyType(
                GetSpecialTaskStamp(),
                Guid.NewGuid().ToString("D"));

            task.ExtendedProperty = new ExtendedPropertyType[] { taskStamp };

            // We will just use a no end recurrence here
            //
            NoEndRecurrenceRangeType noEnd = new NoEndRecurrenceRangeType();

            // Even though we are setting this as a full DateTime, the XML serializer is smart enough
            // to only send across the date part.  Otherwise it would be a schema violation.
            //
            task.StartDate = DateTime.Now.AddDays(-5d); // move back 5 days
            task.StartDateSpecified = true;
            noEnd.StartDate = task.StartDate;
            taskRecurrence.Item1 = noEnd;

            task.Recurrence = taskRecurrence;
            task.Subject = subject;
            task.StartDate = noEnd.StartDate;

            request.Items = new NonEmptyArrayOfAllItemsType();
            request.Items.Items = new ItemType[] { task };

            // Make our CreateItem call
            //
            CreateItemResponseType response = binding.CreateItem(request);
            ItemInfoResponseMessageType responseMessage = response.ResponseMessages.Items[0] as ItemInfoResponseMessageType;
            if (responseMessage.ResponseCode != ResponseCodeType.NoError)
            {
                throw new Exception("Failed to create recurring task.  Response Code: " +
                    responseMessage.ResponseCode.ToString());
            }
            return responseMessage.Items.Items[0].ItemId;
        }

        private const string SpecialTaskStampName = "TaskStamp";
        private static readonly Guid SpecialTaskStampGuid = new Guid("fe43815d-fc44-462d-b1a8-4e3e79b4a487");
        
        /// <summary>
        /// Returns our special task stamp extended field URI
        /// </summary>
        /// <returns>Extended Field URI</returns>
        /// 
        private static PathToExtendedFieldType GetSpecialTaskStamp()
        {
            // Use the factory methods from Chapter 13...
            //
            return PathToExtendedFieldType.BuildGuidName(
                SpecialTaskStampGuid,
                SpecialTaskStampName,
                MapiPropertyTypeType.CLSID);
        }

        /// <summary>
        /// Marks a task as complete by setting the percent complete property to 100
        /// </summary>
        /// <param name="binding">Binding to use</param>
        /// <param name="taskId">Id of the task to complete</param>
        /// <returns>Id of the one-off generated task (in the case of recurring tasks</returns>
        /// 
        public static ItemIdType MarkTaskAsComplete(ExchangeServiceBinding binding, ItemIdType taskId)
        {
            Console.WriteLine("Marking task as complete...");

            UpdateItemType updateRequest = new UpdateItemType();
            updateRequest.ConflictResolution = ConflictResolutionType.AlwaysOverwrite;
            ItemChangeType itemChange = new ItemChangeType();
            itemChange.Item = taskId;

            TaskType newTask = new TaskType();
            newTask.PercentComplete = 100d;
            // Remember that PercentComplete is an optional value type, so set the specified flag.
            //
            newTask.PercentCompleteSpecified = true;

            SetItemFieldType set = new SetItemFieldType(
                new PathToUnindexedFieldType(UnindexedFieldURIType.taskPercentComplete),
                newTask);

            itemChange.Updates = new ItemChangeDescriptionType[] { set };
            updateRequest.ItemChanges = new ItemChangeType[] { itemChange };

            UpdateItemResponseType response = binding.UpdateItem(updateRequest);
            ItemInfoResponseMessageType responseMessage = response.ResponseMessages.Items[0] as ItemInfoResponseMessageType;

            if (responseMessage.ResponseCode != ResponseCodeType.NoError)
            {
                throw new Exception("Failed to mark the task as complete.  Response Code: " +
                    responseMessage.ResponseCode.ToString());
            }
            return responseMessage.Items.Items[0].ItemId;
        }


    }
}
